package com.tianji.StragyHttp.utils;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.tianji.StragyHttp.dto.ExcelExportFiledEntity;
import com.tianji.StragyHttp.enumr.ExportField;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.Cell;
import org.springframework.scheduling.concurrent.CustomizableThreadFactory;
import org.springframework.stereotype.Component;

import java.io.BufferedInputStream;
import java.io.File;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 平台版工具类
 */
@Slf4j
@Component
public class ExportUtil {

    /**
     * 导出线程池
     */
    private static final ExecutorService executorService = new ThreadPoolExecutor(10, 10, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(), new CustomizableThreadFactory("export-pool"));


    /**
     * 平台版通用导出方法，实现函数，填写writer对象
     *
     * @param user         登录商家信息 主要是venderId和sellerNick 可组装传入
     * @param exportRemark 导出备注
     * @param exportType   导出类型
     * @param func         执行方法
     */
    public static void export(UserSession user, String exportRemark, String exportType, Function<ExcelWriter, String> func) {

        try {
            executorService.submit(() -> {
                log.info("导出开始--------------------");
                String path = "C:/exportFiles" + File.separator; //+ fileName;
                File dir = new File("C:/exportFiles");
                if (!dir.exists()) {
                    dir.mkdirs();  // 创建文件夹
                }
                File file = new File(path);
                ExcelWriter writer = ExcelUtil.getWriter(file);
                try {
                    // 执行查询和写入write
                    func.apply(writer);
                    // 写入文件
                    writer.flush(file);
                } catch (Exception e) {
                    log.error(StrUtil.format("导出{}异常", exportType), e);
                } finally {
                    writer.close();
                    file.delete();
                }
                log.info("导出结束--------------------");
            });
        } catch (Exception e) {
            log.error("{} 导出失败", exportType);
            throw e;
        }
    }

    private  String getCellValue(Object target, String fieldName) {
        Object fieldValue = ReflectUtil.getFieldValue(target, fieldName);

        String value;
        if(fieldValue==null){
            return " - ";
        }
        if (fieldValue instanceof String) {
            value = (String) fieldValue;
        } else if(fieldValue instanceof Number) {
            value=((Number) fieldValue).toString();
        }else {
            value = fieldValue.toString();
        }
        return value;
    }

    /**
     * 通用的动态列-行转列 导出方法
     */
    public <V> void customExportDynamicRowToCell(ExcelWriter writer, Class<V> clazz, List<V> vos, List<String> exportColumn, Map<String, String> replaceAliasMap) {
        if (vos.isEmpty()) {
            throw new RuntimeException("没有可以导出的数据");
        }
        writer.setOnlyAlias(true);
        Map<String, ExcelExportFiledEntity> filedEntityMap = getClassFieldAliasMap(clazz, exportColumn, replaceAliasMap);
        Cell cell;
        int row = 0;
        String lastCellValue = "";
        //设置表头 -行转列 后 列数= vos的数据条数 + 原标题行转换列
        for (int i = 0; i < vos.size() + 1; i++) {
            cell = writer.getOrCreateCell(i, row);
            if (i == 0) {
                //第1列，是原第一列的中文标题名
                cell.setCellValue(filedEntityMap.get(exportColumn.get(0)).getAlias());
            } else {
                int idx = i - 1;
                String value = getCellValue(vos.get(idx), exportColumn.get(0));
                if (lastCellValue.equals(value)) {
                    writer.merge(row, row, i - 1, i, value, true);
                } else {
                    cell.setCellValue(value);
                }
                lastCellValue = value;
            }
        }
        //数据行
        for (int r = 0; r < exportColumn.size() - 1; r++) {
            int meRow = row + r + 1;
            StringBuilder rowStr = new StringBuilder();
            //数据列
            for (int x = 0; x <= vos.size(); x++) {
                cell = writer.getOrCreateCell(x, meRow);
                if (x == 0) {
                    //第0列取原标题数据
                    cell.setCellValue(filedEntityMap.get(exportColumn.get(meRow)).getAlias());
                    rowStr.append(cell.getStringCellValue());
                } else {
                    cell.setCellValue(getCellValue(vos.get(x - 1),exportColumn.get(meRow)));
                    rowStr.append(",").append(cell.getStringCellValue());
                }
            }
            log.info("[{}]:{}", meRow, rowStr);
        }
    }

    /**
     * 读取clazz中包含 ExcelProperty 注解的属性，根据index升序设置到ExcelWriter.headerAlias=
     *
     * @param clazz           导出VO映射实体
     * @param exportColumn    自定义动态导出列
     * @param replaceAliasMap <实体属性字段名,需要替换的动态别名>
     */
    private Map<String, ExcelExportFiledEntity> getClassFieldAliasMap(Class<?> clazz, List<String> exportColumn, Map<String, String> replaceAliasMap) {
        List<ExcelExportFiledEntity> fileds = getAlias(clazz);
        if (fileds.isEmpty()) {
            log.error("exportDynamic方法获取导出列为空，请检查返回VO");
            throw new RuntimeException("导出异常，请联系开发");
        }
        Map<String, ExcelExportFiledEntity> filedMaps = fileds.stream().collect(Collectors.toMap(ExcelExportFiledEntity::getField, f -> f, (k1, k2) -> k1));
        for (String column : exportColumn) {
            ExcelExportFiledEntity entity = filedMaps.get(column);
            if (null == entity) {
                throw new RuntimeException("导出异常，动态列名和数据返回实体属性名不一致");
            }
            //如果有需要替换的动态表头字段名，那么执行替换
            if (replaceAliasMap != null && replaceAliasMap.containsKey(entity.getField())) {
                entity.setAlias(replaceAliasMap.get(entity.getField()));
            }
        }
        fileds.clear();
        return filedMaps;
    }
    /**
     * 解析类属性
     */
    private List<ExcelExportFiledEntity> getAlias(Class<?> clazz) {
        List<ExcelExportFiledEntity> fileds = new ArrayList<>(1);
        ExportField annotation;
        boolean needSort = false;
        while (clazz != null && !Object.class.equals(clazz)) {
            // 这里一次性获取了类中的所有元素
            Field[] fields = clazz.getDeclaredFields();
            for (Field field : fields) {
                //检查ExcelProperty注解是否存在
                if (field.isAnnotationPresent(ExportField.class)) {
                    annotation = field.getAnnotation(ExportField.class);
                    if (!needSort && annotation.order() > 0) {
                        needSort = true;
                    }
                    fileds.add(new ExcelExportFiledEntity(field.getName(), annotation.alias(), annotation.order()));
                }
            }
            // 获取所有父类，接着遍历父类中的元素。
            clazz = clazz.getSuperclass();
        }
        if (!fileds.isEmpty()) {
            if (needSort) {
                fileds.sort(Comparator.comparingInt(ExcelExportFiledEntity::getOrder));
            }
        }
        return fileds;
    }

}
